/*Copyright (C) 2009 - 2011 MASSART GAUTHIER and Careil Baptiste

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "../headers.h"

POU_QUIT_T pou_play(POU_CASE_T matrix[POU_MAT_X][POU_MAT_Y], POU_INF_T *inf) {
	bool loop = true;
	POU_QUIT_T ret = POU_QUIT;
	int key, i;

	curs_set(0);
	pou_display_game(matrix, inf);

	while(loop) {
		key = getch();

		if(key == POU_KEY_QUIT) {
			clear();

			if(confirm_str("quitter", TITRE_POUSSE_CAISSE)) {
				loop = false;
				ret = POU_QUIT;
			}
			else {
				pou_display_game(matrix, inf);
			}
		}
		else if(key == POU_KEY_RESTART) {
			clear();

			if(confirm_str("recommencer", TITRE_POUSSE_CAISSE)) {
				ret = POU_RESTART;
				loop = false;
			}
			else {
				pou_display_game(matrix, inf);
			}
		}
		else if(key == POU_KEY_UNDO) {
			pou_undo(inf);
		}
		else {
			pou_move_player(matrix, key, inf);
		}

		if(inf->nb_caisses_restantes == 0 && ret != POU_RESTART) {
			gagner();
			loop = false;
			ret = POU_WIN;
			pou_display_game(matrix, inf);
			getch();
		}
	}

	for(i = 0; i < Container_Size(inf->coups); i++) {
		pou_free_coup(Container_Get(inf->coups, i));
	}

	Container_Clear(&inf->coups);

	return ret;
}

void pou_move_player(POU_CASE_T matrice[POU_MAT_X][POU_MAT_Y], int key, POU_INF_T *inf) {
	IPoint *player_pos, *dir1, *dir2;
	POU_COUPS_T *coup;

	player_pos = malloc(sizeof(IPoint));
	dir1 = malloc(sizeof(IPoint));
	dir2 = malloc(sizeof(IPoint));
	coup = malloc(sizeof(POU_COUPS_T));
	coup->prev_player_cel = &matrice[inf->pos_joueur.x][inf->pos_joueur.y];
	*player_pos = inf->pos_joueur;
	*dir1 = inf->pos_joueur;
	*dir2 = inf->pos_joueur;
	coup->prev_player_pos = player_pos;
	coup->cur_player_pos = dir1;
	coup->cur_player_cel = NULL;
	coup->cur_caisse_pos = dir2;
	coup->cur_caisse_cel = NULL;

	if(key == touche_haut || key == touche_bas) {
		if(key == touche_haut) {
			dir1->y--;
			dir2->y -= 2;
		}
		else {
			dir1->y++;
			dir2->y += 2;
		}

		if(dir1->y >= 0 && dir1->y < POU_MAT_Y) {
			coup->cur_player_cel = &matrice[dir1->x][dir1->y];

			if(dir2->y >= 0 && dir2->y < POU_MAT_Y) {
				coup->cur_caisse_cel = &matrice[dir2->x][dir2->y];
			}

			pou_valid_move(inf, coup);
		}
		else {
			pou_free_coup(coup);
		}
	}
	else if(key == touche_droite || key == touche_gauche) {
		if(key == touche_gauche) {
			dir1->x--;
			dir2->x -= 2;
		}
		else {
			dir1->x++;
			dir2->x += 2;
		}

		if(dir1->x >= 0 && dir1->x < POU_MAT_X) {
			coup->cur_player_cel = &matrice[dir1->x][dir1->y];

			if(dir2->x >= 0 && dir2->x < POU_MAT_X) {
				coup->cur_caisse_cel = &matrice[dir2->x][dir2->y];
			}

			pou_valid_move(inf, coup);
		}
		else {
			pou_free_coup(coup);
		}
	}
	else {
		pou_free_coup(coup);
	}
}

/* Permet de valider, effectuer et afficher un mouvement.
*/
void pou_valid_move(POU_INF_T *inf, POU_COUPS_T *coup) {
	if(*coup->cur_player_cel == POU_MUR) {
		pou_free_coup(coup);
	}
	else {
		if(!(*coup->cur_player_cel & POU_CAISSE)) {
			/* cur_player_cel == (POU_VIDE || POU_TROU) */
			inf->nb_deplacements++;
			inf->pos_joueur = *coup->cur_player_pos;
			*coup->prev_player_cel &= ~POU_JOUEUR;
			*coup->cur_player_cel |= POU_JOUEUR;
			coup->cur_caisse_cel = NULL;
			pou_refresh_coup(coup);
			pou_refresh_inf(inf);
			Container_PushUp(&inf->coups, coup);
		}
		else if(coup->cur_caisse_cel != NULL) {
			/* cur_player_cel == POU_CAISSE || POU_CAISSE|POU_TROU
			   cur_caisse_cel == ? */
			if(*coup->cur_caisse_cel == POU_TROU || *coup->cur_caisse_cel == POU_VIDE) {
				inf->pos_joueur = *coup->cur_player_pos;
				*coup->prev_player_cel &= ~POU_JOUEUR;
				*coup->cur_player_cel |= POU_JOUEUR;
				*coup->cur_player_cel &= ~POU_CAISSE;
				*coup->cur_caisse_cel |= POU_CAISSE;
				inf->nb_deplacements++;

				if(*coup->cur_player_cel & POU_TROU) {
					inf->nb_caisses_restantes++;
				}

				if(*coup->cur_caisse_cel & POU_TROU) {
					inf->nb_caisses_restantes--;
				}

				pou_refresh_coup(coup);
				pou_refresh_inf(inf);
				Container_PushUp(&inf->coups, coup);
			}
			else {
				pou_free_coup(coup);
			}
		}
		else {
			pou_free_coup(coup);
		}
	}
}

void pou_undo(POU_INF_T *inf) {
	POU_COUPS_T *coup;

	if(Container_Size(inf->coups) > 0) {
		coup = Container_Get(inf->coups, 0);
		Container_PopUp(&inf->coups);
		*coup->cur_player_cel &= ~POU_JOUEUR;
		*coup->prev_player_cel |= POU_JOUEUR;
		inf->pos_joueur = *coup->prev_player_pos;

		if(coup->cur_caisse_cel != NULL) {
			if(*coup->cur_caisse_cel & POU_CAISSE) {
				*coup->cur_caisse_cel &= ~ POU_CAISSE;
				*coup->cur_player_cel |= POU_CAISSE;

				if(*coup->cur_caisse_cel == POU_TROU) {
					inf->nb_caisses_restantes++;
				}

				if(*coup->cur_player_cel & POU_TROU) {
					inf->nb_caisses_restantes--;
				}

				pou_refresh_inf(inf);
			}
		}

		pou_refresh_coup(coup);
		pou_free_coup(coup);
	}
}

/* Permet de libéré un coup préalablement alloué.
*/
void pou_free_coup(POU_COUPS_T *coup) {
	free(coup->prev_player_pos);
	free(coup->cur_player_pos);
	free(coup->cur_caisse_pos);
	free(coup);
}
